<?php

declare(strict_types=1);

/**
 * 框架核心函数
 */

use mini\{DB, Session, Flash, Url, Templates};

/**
 * 获取一个数据表操作对象
 *
 * @param  string $table  数据表名称
 * @param  string $item   默认 db , 对应的数据库一级2配置名称
 * @return object         数据库操作对象
 */
function db($table, $item = 'db')
{
    $conf = config($item);
    return DB::getInstance($conf, $table, $item);
}


/**
 * 功能 : 获取一个模型
 * @param  string $modelName  模型名称
 * @return object             模型对象
 */
function model(string $name): object
{
    $modelName = '\\app\\' . MODULE_NAME . '\\models\\' . ucfirst($name);
    if (class_exists($modelName)) {
        $model = new $modelName();
        return $model;
    } else {
        throw new Exception("模型 {$modelName} 不存在");
    }
}


/**
 * 读取配置
 */
function config($key = null)
{
    static $conf = null;

    if ($conf === null) {
        $conf = include ROOT_PATH . 'app/config.php';  
        if (!$conf) {
            throw new Exception('未能加载配置');
        }
    }

    if (is_null($key)) {
        return $conf;
    }

    if (strstr($key, '.') !== '') {
        $keys = explode('.', $key);
        if (empty($keys[1])) {
            return isset($conf[$keys[0]]) ? $conf[$keys[0]] : null;
        }

        return isset($conf[$keys[0]][$keys[1]]) ? $conf[$keys[0]][$keys[1]] : null;
    }

    return isset($conf[$key]) ? $conf[$key] : null;
}

/**
 * 加载视图
 *
 * @param  string $path  视图文件名
 * @param  array  $data  分配的变量
 * @return string
 */
function view(string $path, array $data = []): string
{
    $path = str_replace('.', '/', $path);
    $path = explode('/', $path);

    $file = realpath(APP_PATH . $path[0] . '/views/' . $path[1] . '.php');

    if ($file === false) {
        throw new Exception("模板文件 {$file} 不存在");
    }

    extract($data, EXTR_REFS);

    // ob_start();
    // include $file;
    // $contents = ob_get_contents() ?: '';
    // ob_end_flush();

    ob_start('ob_gzhandler');
    include $file;
    $contents = ob_get_contents();
    ob_end_flush();

    return $contents;
}

/**
     * 加载模板控制器文件，实例化相应的对象，并调用具有给定数据的指定模板方法。
     *
     * @param string $template_name 要调用的模板方法的名称。
     * @param array $data           要传递给模板方法的数据。
     *
     * @return void
     *
     * @throws Exception 如果找不到模板控制器文件或模板方法不存在。
     */
function template(string $template_name, array $data = []): void
{
    $templates = new Templates();
    $template_controller_path = '';

    if (method_exists($templates, $template_name)) {

        if (!isset($data['view_file'])) {
            $data['view_file'] = METHOD_NAME;
        }

        $templates->$template_name($data);
    } else {
        $template_controller_path = str_replace('../', ROOT_PATH, $template_controller_path);
        die('ERROR: Unable to find ' . $template_name . ' method in ' . $template_controller_path . '.');
    }
}

/**
 * 获取分段地址
 */
function segment(int $num, $var_type = null)
{
    $segments = SEGMENTS;

    array_shift($segments);
    
    if (isset($segments[$num])) {
        $value = $segments[$num];
    } else {
        $value = '';
    }

    if (isset($var_type)) {
        settype($value, $var_type);
    }

    return $value;
}

/**
 * 获取请求数据
 */
function post($field_name = false, $clean_up = true)
{
    if (!isset($_POST[$field_name])) {
        $value = '';
    } else {
        $value = $_POST[$field_name];

        if (isset($clean_up)) {
            $value = filter_string($value);

            if (is_numeric($value)) {
                $var_type = (is_numeric(strpos($value, '.'))) ? 'double' : 'int';
                settype($value, $var_type);
            }
        }
    }

    return $value;
}

/**  
 * 获取上一页 URL  
 *  
 * @return string 上一页 URL，如果不存在则返回空字符串  
 * @throws Exception 如果HTTP_REFERER服务器变量非法或不完整  
 */  
function previous_url() {
    if (isset($_SERVER['HTTP_REFERER'])) {
        $referer = $_SERVER['HTTP_REFERER'];
  
        // 对$_SERVER['HTTP_REFERER']进行简单的验证
        if (parse_url($referer, PHP_URL_SCHEME) === null) {
            throw new Exception("referer 方案无效");
        }
  
        if (parse_url($referer, PHP_URL_HOST) === null) {
            throw new Exception("无效的referer主机");
        }
  
        return $referer;
    } else {
        return '';
    }
}

/**  
 * 获取当前页 URL  
 *  
 * @return string 当前页 URL
 */  
function current_url() {
    $current_url = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? "https" : "http") . "://" . $_SERVER['HTTP_HOST'] .  $_SERVER['REQUEST_URI'];
    return $current_url;
}

function asset(string $path = ''): string
{
    return url() . filter_var($path, FILTER_SANITIZE_URL);
}

/**
 * @param  string  $message
 */
function abort($message = '')
{
}

/**
 * 获取上一页
 */
function referer()
{
    return isset($_SERVER['HTTP_REFERER']) ? htmlspecialchars($_SERVER["HTTP_REFERER"]) : '';
}


/**
 * 消毒数据
 *
 * @param  string $data
 * @return string
 */
function sanitize($data)
{
    return trim(escape($data));
}


/**  
 * 获取请求IP  
 *  
 * @return string 客户端的IP地址  
 */  
function get_ip() {  
    if (isset($_SERVER['HTTP_CLIENT_IP']) && $_SERVER['HTTP_CLIENT_IP'] !== 'unknown') {
        $ip = $_SERVER['HTTP_CLIENT_IP'];
    } elseif (isset($_SERVER['HTTP_X_FORWARDED_FOR']) && $_SERVER['HTTP_X_FORWARDED_FOR'] !== 'unknown') {
        $ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
    } elseif (isset($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] !== 'unknown') {
        $ip = $_SERVER['REMOTE_ADDR'];
    } else {
        $ip = '127.0.0.1';
    }
  
    // 使用正则表达式过滤IP地址，如果匹配成功则返回匹配到的第一个IP，否则返回127.0.0.1
    return preg_match('/[\d\.]{7,15}/', $ip, $matches) ? $matches[0] : '127.0.0.1';
}

function flash(string $name = '', string $message = '')
{
    Flash::add($name, $message);
}

/**
 * @param  string|null  $to
 * @param  int  $status
 */
function redirect(string $to = null, int $status = 302)
{
    $url = filter_var($to, FILTER_SANITIZE_URL);
    header('Location: ' . $url, true, $status);
    exit(1);
}

function session(string $key)
{
    return Session::has($key) ? Session::get($key) : false;
}

function csrf_token(int $length = 32)
{
    return Session::getToken($length);
}

function url(string $path = ''): string
{
    return Url::home() . filter_var($path, FILTER_SANITIZE_URL);
}

/**
 * 输出 json
 */
function json($msg, string $status = 'error')
{
    // header('Content-Type: application/json; charset=utf-8');
    echo json_encode(
        [
            'message' => escape($msg),
            'status'  => $status
        ],
        JSON_UNESCAPED_UNICODE | JSON_INVALID_UTF8_SUBSTITUTE
    );
}

/**
 * 检查请求方法是否为 ajax
 *
 * @return boolean
 */
function is_ajax(): bool
{
    return isset($_SERVER['HTTP_X_REQUESTED_WITH'])   
        && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) === 'xmlhttprequest';
}

/**
 * 检测是否使用手机访问
 *
 * @return bool
 */
function is_mobile(): bool
{
    if (isset($_SERVER['HTTP_VIA']) && stristr($_SERVER['HTTP_VIA'], "wap")) {
        return true;
    } elseif (isset($_SERVER['HTTP_ACCEPT']) && strpos(strtoupper($_SERVER['HTTP_ACCEPT']), "VND.WAP.WML")) {
        return true;
    } elseif (isset($_SERVER['HTTP_X_WAP_PROFILE']) || isset($_SERVER['HTTP_PROFILE'])) {
        return true;
    } elseif (isset($_SERVER['HTTP_USER_AGENT']) && preg_match('/(blackberry|configuration\/cldc|hp |hp-|htc |htc_|htc-|iemobile|kindle|midp|mmp|motorola|mobile|nokia|opera mini|opera |Googlebot-Mobile|YahooSeeker\/M1A1-R2D2|android|iphone|ipod|mobi|palm|palmos|pocket|portalmmm|ppc;|smartphone|sonyericsson|sqh|spv|symbian|treo|up.browser|up.link|vodafone|windows ce|xda |xda_)/i', $_SERVER['HTTP_USER_AGENT'])) {
        return true;
    } else {
        return false;
    }
}



/**
 * 打印变量
 */
function dump($value)
{
    echo '<pre>';
    var_dump($value);
    echo '</pre>';
}

/**
 * 打印变量然后退出
 */
function dd($value)
{
    echo '<pre>';
    var_dump($value);
    echo '</pre>';
    exit(1);
}

/**
 * 页面不存在
 * 
 * @param string $msg 错误信息
 */
function page_not_found($msg = '当前页面无法访问，可能没权限或已删除。')
{
    http_response_code(404);
    header('HTTP/1.1 404 Not Found');
    require_once dirname(__DIR__).'/templates/404.php';
}

/**
 * 输出 radio ,checkbox 选中状态
 * @param string $val1 比对值1
 * @param string $val2 比对值2
 */
function is_checked($val1, $val2)
{
    if ($val1 === $val2) {
        echo "checked";
    }
}

/**
 * 输出 option 选中状态
 * @param $val1 比对值1
 * @param $val2 比对值2
 */
function is_option_selected($optionValue, $compareValue) { 
    if ($optionValue === $compareValue) {
        echo ' selected="selected"';
    }
}


/**
 * 规划缓存命名
 *
 * @param  string  $name      缓存名称
 * @param  mixed   $parameter 缓存影响参数
 * @param  boolean $isSuper   是否为全局缓存
 * @return string 缓存名称
 */
function setCacheName($name, $parameter = '', $isSuper = true)
{
    $cacheConfig = config('cache');
    $parameter   = is_array($parameter) ? implode('_', $parameter) : $parameter;
    $cacheName   = $isSuper ? $cacheConfig['pre'] . $name . $parameter : $cacheConfig['pre'] . 'PG_C' . '_' . 'PG_M' . '_' . $name . $parameter;
    if (empty($cacheConfig['name2md5'])) {
        return $cacheName;
    }
    return hash('sha384', $cacheName);
}

/**
 * 可能适用于筛选通过文本区域提交的数据
 */
function filter_string($string, $allowed_tags = [])
{
    // 删除HTML和PHP标记（请阅读上面的注释了解更多信息！）
    $string = strip_tags($string, $allowed_tags);

    // 应用 XSS 筛选
    $string = htmlspecialchars($string);

    // 将多个连续空格转换为一个空格，换行除外
    $string = preg_replace('/[^\S\r\n]+/', ' ', $string);

    // 修剪前导和尾随空白
    $string = trim($string);

    return $string;
}


/**
 * 过滤变量
 */
function escape($value = null)
{
    if (is_array($value)) {
        foreach ($value as $k => $v) {
            $value[$k] = is_string($v) ? htmlspecialchars($v, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8') : filter_var($v, FILTER_SANITIZE_NUMBER_FLOAT);
        }
        return $value;
    }

    if (is_string($value)) {
        return htmlspecialchars($value, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
    }

    if (is_int($value) || is_float($value)) {
        return filter_var($value, FILTER_SANITIZE_NUMBER_FLOAT);
    }

    // 额外的异常处理
    if (!is_scalar($value) || $value === null) {
        throw new Exception('意外的值类型');
    }
}


/**
 * 去除空白字符
 * @param  string  $str 需要替换的字符串
 * @return string  替换后的结果
 */
function trim_space($str)
{
    $search  = array(" ", "　", "\t", "\n", "\r");
    $replace = array("", "", "", "", "");
    return str_replace($search, $replace, $str);
}

/**
 * 友好的时间显示
 */
function nice_time($time)
{
    $t = time() - $time;
    $f = [
        '31536000' => '年',
        '2592000'  => '个月',
        '604800'   => '星期',
        '86400'    => '天',
        '3600'     => '小时',
        '60'       => '分钟',
        '1'        => '秒'
    ];
    foreach ($f as $k => $v) {
        if (0 != $c = floor($t / (int)$k)) {
            return $c . $v . '前';
        }
    }
}


/**
 * 格式化文件大小
 */
function format_size($size, $precision = 2)
{
    $units = [' 字节', ' KB', ' MB', ' GB', ' TB'];
    for ($i = 0; $size >= 1024 && $i < 4; $i++) {
        $size /= 1024;
    }
    return round($size, $precision) . $units[$i];
}

/**
 * 登录或注册后跳转到之前页面
 */
function go_back()
{
    if (session('backToLink')) {
        $backToLink = realpath(session('backToLink'));
        return redirect(url($backToLink));
    }

    return redirect(url('/'));
}

/**
 * 随机显示颜色
 */
function rand_color()
{
    $colors = ['#F5FBF7', '#FEF7E0', '#F8F9FA', '#D9534F', '#B37333', '#00ABA9'];
    $key = array_rand($colors, 1);
    return $colors[$key];
}
